
#include "stdlib.h"
#include "ohos_init.h" // 用于初始化服务(services)和功能(features)
#include "cmsis_os2.h" // CMSIS-RTOS API V2

// lwIP：A Lightweight TCPIP stack
// 瑞典计算机科学院(SICS)的Adam Dunkels开发的一个小型(轻量)开源的TCP/IP协议栈
// 实现的重点是在保持TCP协议主要功能的基础上减少对RAM的占用
// 仅占用几十KB RAM空间，40KB ROM空间，非常适合在嵌入式系统中使用
//
// lwIP TCP/IP协议栈：网络接口API
// netifapi：Network Interfaces API
#include "lwip/netifapi.h"
//
// lwIP TCP/IP协议栈：SHELL命令API
// #include "lwip/api_shell.h"
#include "lwip/nettool/misc.h"

#include "soc_osal.h"
#include "errcode.h"
#include "wifi_device.h"
#include "wifi_hotspot.h"
#include "wifi_hotspot_config.h"
#include "wifi_linked_info.h"
#include "wifi_device_config.h"

#include "station_demo.h"
#include "mqtt_main.h"              // mqtt_start_task, mqtt_stop_task  

#define WIFI_IFNAME_MAX_SIZE 16
#define WIFI_SCAN_AP_LIMIT 64
#define WIFI_CONN_STATUS_MAX_GET_TIMES 5   /* 启动连接之后，判断是否连接成功的最大尝试次数 */
#define DHCP_BOUND_STATUS_MAX_GET_TIMES 20 /* 启动DHCP Client端功能之后，判断是否绑定成功的最大尝试次数 */
#define WIFI_STA_IP_MAX_GET_TIMES 5        /* 判断是否获取到IP的最大尝试次数 */

#define SSID "home"          //"HUAWEI-Dragon"
#define KEY  "12345678"     //Good@123!"

int g_ConnectSuccess = 0;               // 供外部使用: 1表示wifi成功

// 1) 读取设备mac地址，无需联网成功，只需要 enable wifi 
int GetDeviceMac(char *mac)
{
    if(g_ConnectSuccess==0){
        return 0;
    } 
    else {
        unsigned char mac2[6] = {0};
        GetDeviceMacAddress(mac2);    
        snprintf(mac, 12+1, "%02x%02x%02x%02x%02x%02x", mac2[0], mac2[1], mac2[2], mac2[3], mac2[4], mac2[5]);
        //printf("+++ GetDeviceMacAddress: %s \r\n", mac);
        return 1;
    } 
}


// STA 扫描-关联
static errcode_t get_match_network(const char *expected_ssid,
                                   const char *key,
                                   wifi_sta_config_stru *expected_bss)
{
    uint32_t num = WIFI_SCAN_AP_LIMIT; /* 64:扫描到的Wi-Fi网络数量 */
    uint32_t bss_index = 0;

    /* 获取扫描结果 */
    uint32_t scan_len = sizeof(wifi_scan_info_stru) * WIFI_SCAN_AP_LIMIT;
    wifi_scan_info_stru *result = osal_kmalloc(scan_len, OSAL_GFP_ATOMIC);
    if (result == NULL)
    {
        return ERRCODE_MALLOC;
    }
    memset_s(result, scan_len, 0, scan_len);
    if (wifi_sta_get_scan_info(result, &num) != ERRCODE_SUCC)
    {
        osal_kfree(result);
        return ERRCODE_FAIL;
    }

    /* 筛选扫描到的Wi-Fi网络，选择待连接的网络 */
    for (bss_index = 0; bss_index < num; bss_index++)
    {
        if (strlen(expected_ssid) == strlen(result[bss_index].ssid))
        // if (strcmp(expected_ssid, result[bss_index].ssid) == 0)
        {
            if (memcmp(expected_ssid, result[bss_index].ssid, strlen(expected_ssid)) == 0)
            {
                break;
            }
        }
    }

    /* 未找到待连接AP,可以继续尝试扫描或者退出 */
    if (bss_index >= num)
    {
        osal_kfree(result);
        return ERRCODE_FAIL;
    }

    /* 找到网络后复制网络信息和接入密码 */
    if (memcpy_s(expected_bss->ssid, WIFI_MAX_SSID_LEN, result[bss_index].ssid, WIFI_MAX_SSID_LEN) != EOK)
    {
        osal_kfree(result);
        return ERRCODE_MEMCPY;
    }
    // 非必须
    // if (memcpy_s(expected_bss->bssid, WIFI_MAC_LEN, result[bss_index].bssid, WIFI_MAC_LEN) != EOK)
    // {
    //     osal_kfree(result);
    //     return ERRCODE_MEMCPY;
    // }
    expected_bss->security_type = result[bss_index].security_type;
    if (memcpy_s(expected_bss->pre_shared_key, WIFI_MAX_KEY_LEN, key, strlen(key)) != EOK)
    {
        osal_kfree(result);
        return ERRCODE_MEMCPY;
    }
    expected_bss->ip_type = DHCP; /* IP类型为动态DHCP获取 */
    osal_kfree(result);
    return ERRCODE_SUCC;
}

//static errcode_t 
int ConnectToHotspot(void)
{
    /* WiFi STA 网络设备名，SDK默认是wlan0, 以实际名称为准 */
    char ifname[WIFI_IFNAME_MAX_SIZE + 1] = "wlan0";

    /* 连接请求信息 */
    wifi_sta_config_stru expected_bss = {0};

    // 有关连接到此STA的AP信息
    wifi_linked_info_stru wifi_status;

    /* 待连接的网络名称 */
    const char expected_ssid[] = SSID;

    /* 待连接的网络接入密码 */
    const char key[] = KEY;

    /* 延时5s，等待wifi初始化完毕 */
    osal_msleep(5000);

    /* 创建STA */
    osal_printk("STA try enable.\r\n");
    if (wifi_sta_enable() != ERRCODE_SUCC)
    {
        osal_printk("sta enbale fail !\r\n");
        return -1; //ERRCODE_FAIL;
    }

    // 扫描并连接到AP
    do
    {
        // 启动STA扫描。每次触发扫描至少间隔1s
        osal_msleep(1000);
        osal_printk("Start Scan !\r\n");
        if (wifi_sta_scan() != ERRCODE_SUCC)
        {
            osal_printk("STA scan fail, try again !\r\n");
            continue;
        }

        /* 延时3s, 等待扫描完成 */
        osal_msleep(3000);

        /* 获取待连接的网络 */
        if (get_match_network(expected_ssid, key, &expected_bss) != ERRCODE_SUCC)
        {
            osal_printk("Can not find AP, try again !\r\n");
            continue;
        }

        osal_printk("STA try connect...\r\n");
        /* 启动连接 */
        if (wifi_sta_connect(&expected_bss) != ERRCODE_SUCC)
        {
            continue;
        }

        /* 检查网络是否连接成功 */
        uint8_t index = 0;
        for (index = 0; index < WIFI_CONN_STATUS_MAX_GET_TIMES; index++)
        {
            osal_msleep(500); /* 延时500ms */
            memset_s(&wifi_status, sizeof(wifi_linked_info_stru), 0, sizeof(wifi_linked_info_stru));
            if (wifi_sta_get_ap_info(&wifi_status) != ERRCODE_SUCC)
            {
                continue;
            }
            if (wifi_status.conn_state == WIFI_CONNECTED)
            {
                break;
            }
        }

        if (wifi_status.conn_state == WIFI_CONNECTED)
        {
            break; /* 连接成功退出循环 */
        }
    } while (1);

    /* DHCP获取IP地址 */
    // 获取网络接口
    osal_printk("STA DHCP start.\r\n");
    struct netif *netif_p = NULL;
    netif_p = netifapi_netif_find(ifname);
    if (netif_p == NULL)
    {
        return -1;//ERRCODE_FAIL;
    }

    // 启动DHCP客户端
    if (netifapi_dhcp_start(netif_p) != ERR_OK)
    {
        osal_printk("STA DHCP Fail.\r\n");
        return -1;//ERRCODE_FAIL;
    }

    // 等待绑定成功
    for (uint8_t i = 0; i < DHCP_BOUND_STATUS_MAX_GET_TIMES; i++)
    {
        osal_msleep(500); /* 延时500ms */
        if (netifapi_dhcp_is_bound(netif_p) == ERR_OK)
        {
            osal_printk("STA DHCP bound success.\r\n");
            break;
        }
    }

    // 等待DHCP服务端分配IP地址
    for (uint8_t i = 0; i < WIFI_STA_IP_MAX_GET_TIMES; i++)
    {
        osal_msleep(10); /* 延时10ms */
        if (netif_p->ip_addr.u_addr.ip4.addr != 0)
        {
            osal_printk("STA IP %u.%u.%u.%u\r\n", (netif_p->ip_addr.u_addr.ip4.addr & 0x000000ff),
                   (netif_p->ip_addr.u_addr.ip4.addr & 0x0000ff00) >> 8,
                   (netif_p->ip_addr.u_addr.ip4.addr & 0x00ff0000) >> 16,
                   (netif_p->ip_addr.u_addr.ip4.addr & 0xff000000) >> 24);
            netifapi_netif_common(netif_p, dhcp_clients_info_show, NULL);
            if (netifapi_dhcp_start(netif_p) != 0)
            {
                osal_printk("STA DHCP Fail.\r\n");
                return -1;// ERRCODE_FAIL;
            }

            /* 连接成功 */
            osal_printk("STA connect success. == LAMP \r\n");

            // 往外部传递wifi连接状态
            g_ConnectSuccess = 1;            

            return 0;  //ERRCODE_SUCC;
        }
    }

    osal_printk("STA connect fail.\r\n");
    return -1;//ERRCODE_FAIL;
}
 